﻿namespace WebPacker.Tests.Filters
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;
	using NUnit.Framework;
	using WebPacker.Filters;
	using WebPacker.Packs;

	[TestFixture]
	public class FilterCollectionTest
	{
		[Test]
		public void AddNullTest()
		{
			var collection = new FilterCollection();
			Assert.Throws<ArgumentNullException>(() => collection.Add(null));
		}

		[Test]
		public void AddTest()
		{
			var collection = new FilterCollection();
			collection.Add(new YuiCssMinifier() { Name = "css" });
			Assert.AreEqual(1, collection.Count);
		}

		[Test]
		public void AddComplexTest()
		{
			var collection = new FilterCollection();
			collection.Add(new YuiCssMinifier() { Name = "css" });
			collection.Add(new YuiCssMinifier() { Name = "CSS" });
			collection.Add(new YuiJavascriptMinifier() { Name = "css" });
			Assert.AreEqual(3, collection.Count);
		}

		[Test]
		public void AddRangeTest()
		{
			var collection = new FilterCollection();
			var filters = GetTestFilters();
			collection.AddRange(filters);
			Assert.AreEqual(filters.Length, collection.Count);
		}

		[Test]
		public void AddUniqueConstraintTest()
		{
			var collection = new FilterCollection();
			collection.Add(new YuiCssMinifier { Name = "css" });
			Assert.Throws<ArgumentException>(() => collection.Add(new YuiCssMinifier { Name = "css" }));
			Assert.AreEqual(1, collection.Count);
		}

		[Test]
		public void GetItemTest()
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);

			foreach (var filter in filters)
			{
				Assert.AreSame(filter, collection.GetItem(filter.PackType, filter.Name));
			}
		}

		[Test]
		public void GetDefaultItemTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType)
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);
			var expected = filters.Where(x => x.PackType == packType).First();
			Assert.AreEqual(expected, collection.GetItem(packType));
		}

		[Test]
		public void GetDefaultItemErrorTest()
		{
			var filters = new IFilter[]
			{
				new YuiCssMinifier { Name = "css" },
				new YuiCssMinifier { Name = "css2" }
			};

			var collection = new FilterCollection();
			collection.AddRange(filters);

			Assert.Throws<ArgumentException>(() => collection.GetItem(PackType.JavaScript));
		}

		[Test]
		public void ContainsTest()
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);

			foreach (var filter in filters)
			{
				Assert.IsTrue(collection.Contains(filter.PackType, filter.Name));
			}
		}

		[Test]
		public void TryGetItemTest()
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);

			foreach (var expected in filters)
			{
				IFilter actual;
				Assert.IsTrue(collection.TryGetItem(expected.PackType, expected.Name, out actual));
				Assert.AreSame(expected, actual);
			}
		}

		[Test]
		public void TryGetDefaultItemTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType)
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);
			var expected = filters.Where(x => x.PackType == packType).First();
			IFilter actual;
			Assert.IsTrue(collection.TryGetItem(packType, out actual));
			Assert.AreEqual(expected, actual);
		}

		[Test]
		public void TryGetDefaultItemErrorTest()
		{
			var filters = new IFilter[]
			{
				new YuiJavascriptMinifier { Name = "js2" },
				new YuiJavascriptMinifier { Name = "js1" }
			};

			var collection = new FilterCollection();
			collection.AddRange(filters);

			IFilter filter;
			Assert.IsFalse(collection.TryGetItem(PackType.Css, out filter));
			Assert.IsNull(filter);
		}

		[Test]
		public void GetItemFailedTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType,
			[Values("unknown1", "JS1")]
			string packName)
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);
			Assert.Throws<ArgumentException>(() => collection.GetItem(packType, packName));
		}

		[Test]
		public void TryGetItemFailedTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType,
			[Values("CSS1", "JS1")]
			string packName)
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);
			IFilter actual;
			Assert.IsFalse(collection.TryGetItem(packType, packName, out actual));
			Assert.IsNull(actual);
		}

		[Test]
		public void ContainsFailedTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType,
			[Values("CSS1", "JS1")]
			string packName)
		{
			var filters = GetTestFilters();
			var collection = new FilterCollection();
			collection.AddRange(filters);
			Assert.IsFalse(collection.Contains(packType, packName));
		}

		[Test]
		public void RemoveTest()
		{
			var collection = new FilterCollection();
			collection.Add(new YuiCssMinifier() { Name = "css" });
			Assert.IsTrue(collection.Remove(PackType.Css, "css"));
			Assert.AreEqual(0, collection.Count);
		}

		[Test]
		public void RemoveFailedTest()
		{
			var collection = new FilterCollection();
			collection.Add(new YuiCssMinifier() { Name = "css" });
			Assert.IsFalse(collection.Remove(PackType.JavaScript, "css"));
			Assert.IsFalse(collection.Remove(PackType.Css, "CSS"));
			Assert.AreEqual(1, collection.Count);
		}

		private IFilter[] GetTestFilters()
		{
			return new IFilter[]
			{
				new YuiCssMinifier { Name = "css" },
				new YuiCssMinifier { Name = "css2" },
				new YuiJavascriptMinifier { Name = "js" }
			};
		}
	}
}
